[iOS] UIViewPropertyAnimatorに良い感じのイージングを使いたい!
こんにちは。きんくまです。
アニメーションのキモはイージング!ということで、今回はカスタムイージングのお話です。
まずはデモを見てください。
これは、左から右に1秒で移動するだけのアニメーションなのですが、1点だけ違いがあって、それはイージングです。
イージングとは?
昔書いた記事があるのですが、時間を等間隔に分割して、その位置を変更すると、アニメーションの動きが全然変わって見えるのです。
UIViewのアニメーションでやりたい
UIViewのアニメーションはこんな感じにやります。
オプションのところが curveEaseIn
のように指定できるのですが種類が少なくてちょっと寂しいところでした。
UIView.animate(withDuration: 1.0, delay: 0, options: [.curveEaseIn], animations: { }, completion: nil)
UIViewPropertyAnimatorでカスタムイージングを指定できる!
そこでUIViewPropertyAnimatorの登場です。これには、自分で設定したイージングを設定できるのです。すばらしいっ!
今回作ったパラメータ
/// ベジェタイミングタイプ /// /// オリジナルパラメータ /// https://github.com/zz85/cubic-bezier-approximations enum CubicTimingParametersType { case quadIn case quadOut case quadInOut case cubicIn case cubicOut case cubicInOut case quartIn case quartOut case quartInOut case quintIn case quintOut case quintInOut case sineIn case sineOut case sineInOut case expoIn case expoOut case expoInOut case circIn case circOut case circInOut var controlPointData: [CGFloat] { switch self { case .quadIn: return [ 0.26, 0, 0.6, 0.2 ] case .quadOut: return [ 0.4, 0.8, 0.74, 1 ] case .quadInOut: return [ 0.48, 0.04, 0.52, 0.96 ] case .cubicIn: return [ 0.4, 0, 0.68, 0.06 ] case .cubicOut: return [ 0.32, 0.94, 0.6, 1 ] case .cubicInOut: return [ 0.66, 0, 0.34, 1 ] case .quartIn: return [ 0.52, 0, 0.74, 0 ] case .quartOut: return [ 0.26, 1, 0.48, 1 ] case .quartInOut: return [ 0.76, 0, 0.24, 1 ] case .quintIn: return [ 0.64, 0, 0.78, 0 ] case .quintOut: return [ 0.22, 1, 0.36, 1 ] case .quintInOut: return [ 0.84, 0, 0.16, 1 ] case .sineIn: return [ 0.32, 0, 0.6, 0.36 ] case .sineOut: return [ 0.4, 0.64, 0.68, 1 ] case .sineInOut: return [ 0.36, 0, 0.64, 1 ] case .expoIn: return [ 0.66, 0, 0.86, 0 ] case .expoOut: return [ 0.14, 1, 0.34, 1 ] case .expoInOut: return [ 0.9, 0, 0.1, 1 ] case .circIn: return [ 0.54, 0, 1, 0.44 ] case .circOut: return [ 0, 0.56, 0.46, 1 ] case .circInOut: return [ 0.88, 0.14, 0.12, 0.86 ] } } } /// UICubicTimingParametersを作成する class CubicTimingParametersCreator { static func createParameters(timingType: CubicTimingParametersType) -> UICubicTimingParameters { let pointData = timingType.controlPointData if pointData.count != 4 { fatalError("the count of pointData must be 4") } let pt1 = CGPoint(x: pointData[0], y: pointData[1]) let pt2 = CGPoint(x: pointData[2], y: pointData[3]) return UICubicTimingParameters(controlPoint1: pt1, controlPoint2: pt2) } }
これを使ってみます。
//UIViewPropertyAnimatorをイージングを指定して作成! let params = CubicTimingParametersCreator.createParameters(timingType: timingCurve) let animator = UIViewPropertyAnimator(duration: 1.0, timingParameters: params) //アニメーションの内容 let halfSquareW = squareWidth / 2 let centerY = squareY + halfSquareW animationSquare.center = CGPoint(x: halfSquareW, y: centerY) animator.addAnimations { [weak self] in guard let self = self else { return } let screenW = UIScreen.main.bounds.width self.animationSquare.center = CGPoint(x: screenW - halfSquareW, y: centerY) } propertyAnimator = animator //スタート animator.startAnimation()
作ったリポジトリ
cm-tsmaeda/CubicVezierCurveSample
こんな感じにUIViewのアニメーションにもカスタムイージングが指定してできて嬉しい!という話でした。
余談
UIViewPropertyAnimatorで指定できるようになる前にも、カスタムイージングを使ってアニメーションすることができました。
ただ、それはCALayerに対してだけでした。
それで以前、それ用のクラスを書いたこともありました。
KinkumaDesign/CustomMediaTimingFunction
今回作ったイージングのパラメータは、こちらのリポジトリからいただいています。
zz85/cubic-bezier-approximations
その中に私の作ったパラメータが比較対象で載っけてもらっていました。
zz85さんのものは、たぶんプログラム的にコントロールポイントを求めたものだと思うので、私の作ったやつより正確だと思います。(私のは自前のツールを作って手動で値をとったものでしたw)
なので良かったなーと思った次第です。